package com.shhm.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.shhm.common.constants.HttpStatus;
import com.shhm.common.dto.response.AjaxResultPlus;
import com.shhm.common.entity.system.SysMenu;
import com.shhm.common.entity.admin.SysUser;
import com.shhm.common.entity.system.UserDetailResp;
import com.shhm.common.entity.system.UserRole;
import com.shhm.common.utils.*;
import com.shhm.system.dto.request.UserFormVO;
import com.shhm.system.mapper.LoginMapper;
import com.shhm.system.mapper.SysUserRoleMapper;
import com.shhm.system.service.LoginService;
import com.shhm.system.service.SysUserRoleService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author JackZ
 * @version 1.0
 * @description: 登录接口
 * @date 2025/7/12 下午6:49
 */
@Service
public class LoginSrviceImpl implements LoginService {
    @Resource
    private LoginMapper loginMapper;
    @Resource
    @Qualifier("captchaProducerMath") // 指定数学验证码 Bean
    private DefaultKaptcha kaptchaBeanMath;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SysUserRoleService sysUserRoleService;


    @Override
    public AjaxResultPlus getInfo(UserFormVO reqUser,HttpServletRequest request) {
//        验证码校验
        String passCheck= CaptchaUtil.checkCaptcha(request,redisTemplate,reqUser.getCaptcha(),RedisUtil.REDIS_LOGIN_KEY);
        if(!passCheck.equals("pass")) return AjaxResultPlus.warn(passCheck);

//        校验用户信息
//        LambdaQueryWrapper<SysUser> lambda = new LambdaQueryWrapper<>();
//        lambda.eq(SysUser::getUsername,reqUser.getUsername())
//                .eq(SysUser::getStatus,0);
//        SysUser info = loginMapper.selectOne(lambda);

        UserDetailResp info=loginMapper.loginOperate(reqUser);

        if (info == null||!passwordEncoder.matches(reqUser.getPassword(),info.getPassword())) {
            return AjaxResultPlus.warn("用户名或密码错误!");
        }

//        查询角色
        List<UserRole> sur = sysUserRoleMapper.selectRolesByUserId(info.getUserId());

//        创建令牌
        String token = JwtUtil.createToken(info.getUsername(),info.getRealName(), info.getUserId(), sur);

//        将令牌存入redis
        String jsonUser = JSON.toJSONString(info);
        Object isLogoutInfo = redisTemplate.opsForValue().get(RedisUtil.REDIS_BLACK_TOKEN_KEY + info.getUserId());
        if (Objects.nonNull(isLogoutInfo)) redisTemplate.delete(RedisUtil.REDIS_BLACK_TOKEN_KEY + info.getUserId());
        redisTemplate.opsForValue().set(RedisUtil.REDIS_USER_ONLINE_KEY+info.getUserId(),jsonUser,30,TimeUnit.MINUTES);
        redisTemplate.opsForValue().set(RedisUtil.REDIS_TOKEN_ONLINE_KEY+info.getUserId(),token,30,TimeUnit.MINUTES);

//        获取用户菜单列表
        List<SysMenu> routerList = sysUserRoleService.getRouterList(info.getUserId());

//        处理并返回数据
        info.setPassword("-1");
        return AjaxResultPlus.custom(HttpStatus.SUCCESS,true)
                .put("msg","登陆成功!")
                .put("token", token)
                .put("user",info)
                .put("roles",sur)
                .put("routerList",routerList);
    }

    /**
     * 查看验证码是否通过
     * @param request
     * @return
     */
    private String checkCaptcha(HttpServletRequest request,Integer codeAns) {
        //        获取ip
        String ipAddress = IpUtil.getIpAddress(request);
        String key = RedisUtil.REDIS_LOGIN_KEY + ipAddress;
        Object r_data = redisTemplate.opsForValue().get(key);

//        判断是否存在
        if (Objects.isNull(r_data)) return "验证码不存在或已过期!";

//        获取验证码和验证次数
        Map r_d = JSON.parseObject((String) r_data, Map.class);
        String captcha_code = (String)r_d.get("code");
        int r_ans = Integer.parseInt(captcha_code);

        String captcha_num = (String) r_d.get("maxRetry");
        Integer r_cn = Integer.parseInt(captcha_num);

//        判断校验次数过多则销毁该验证码
        if (r_cn==0) {
            redisTemplate.delete(key);
            return "您已多次校验错误，将刷新验证码!";
        }

            //判断验证是否成功
        if (r_ans!=codeAns) {
            r_cn--;
            String r_scn=r_cn.toString();
            sr_data(captcha_code,key,r_scn);
            return "验证码错误!";
        }

//        通过验证并销毁验证码
        redisTemplate.delete(key);
        return "pass";
    }

    @Override
    public AjaxResultPlus getCaptcha(HttpServletRequest request) throws IOException {
        return CaptchaUtil.getCaptcha(request,redisTemplate,kaptchaBeanMath,RedisUtil.REDIS_LOGIN_KEY);
    }

    /**
     * redis存储数据
     * @param code
     * @param key
     */
    private void sr_data(String code,String key,String retryNum){
        HashMap<String, Object> rv_data = new HashMap<>();
        rv_data.put("maxRetry",retryNum);
        rv_data.put("code",code);
        redisTemplate.opsForValue().set(key,JSON.toJSONString(rv_data),5,TimeUnit.MINUTES);
    }

    /**
     * 图片转base64
     * @param image
     * @return
     * @throws IOException
     */
    private String ImageToBase64(BufferedImage image) throws IOException {
        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
        ImageIO.write(image,"jpg",outstream);
        return Base64.getEncoder().encodeToString(outstream.toByteArray());
    }

    /**
     * 退出登录
     * @param req
     * @return
     */
    @Override
    public AjaxResultPlus loginOut(HttpServletRequest req) {
        String token = JwtUtil.handleAuthorizationString(req.getHeader("Authorization"));
        if (!JwtUtil.isExpired(token)) {
            Integer uid = JwtUtil.getUIDFromToken(token);
            long expired = JwtUtil.getExpired(token)+1;
            redisTemplate.opsForValue().set(RedisUtil.REDIS_BLACK_TOKEN_KEY+uid,token,expired,TimeUnit.SECONDS);
            redisTemplate.delete(RedisUtil.REDIS_USER_ONLINE_KEY+uid);
            redisTemplate.delete(RedisUtil.REDIS_TOKEN_ONLINE_KEY+uid);
        }
        return AjaxResultPlus.warn("已退出账号");
    }
}
